/*
* @Author: Adolphus.Yao
* @Date:   2019-07-23 17:17:49
* @Last Modified by:   Adolphus.Yao
* @Last Modified time: 2019-10-16 21:23:38
*/
package main

import (
    "flag"
    "bufio"
    "fmt"
    "io"
    "os"
    "strings"
    "encoding/json"
)

var (
    h bool
    file_path string
)

func init() {
    flag.BoolVar(&h, "h", false, "this help")
    flag.StringVar(&file_path, "f", "out.txt", "set json datas file")

    // 改变默认的 Usage，flag包中的Usage 其实是一个函数类型。这里是覆盖默认函数实现，具体见后面Usage部分的分析
    flag.Usage = usage
}

func main() {
    flag.Parse()

    if h {
        flag.Usage()
    } else {
        fi, err := os.Open(file_path)
        if err != nil {
            fmt.Printf("Error: %s\n", err)
            return
        }
        defer fi.Close()

        br := bufio.NewReader(fi)
        lineNo := 0
        for {
            lineNo++
            line, err := br.ReadString('\n')
            line = strings.TrimSpace(line)
            if err != nil {
                if io.EOF == err {   //读取结束，会报EOF
                    break
                }
                fmt.Println(err, " err!!!!!!!!!! ", lineNo)
                continue
            }
            if 0 < len(line) {
                checkJson(line, lineNo)
            }
        }
    }
}

func usage() {
    fmt.Fprintf(os.Stderr, `jcheck version: jcheck/1.0.0
Usage: jcheck

Options:
`)
    flag.PrintDefaults()
}

func checkJson(jsonStr string, lineNo int) {
    var jsonMap map[string]interface{}
    //使用 json.Unmarshal(data []byte, v interface{})进行转换,返回 error 信息
    if err := json.Unmarshal([]byte(jsonStr), &jsonMap); err != nil {
        fmt.Println(err, jsonStr, " err!!!!!!!!!! ", lineNo)
        return
    }

    _card_list, err := getValue(jsonMap, "card_list")
    if nil != err {
        fmt.Println(err, jsonStr, " err!!!!!!!!!! ", lineNo)
        return
    }
    card_list, ok := _card_list.([]interface{})
    if !ok {
        fmt.Println(fmt.Errorf("%s", "card_list this data is not list"))
        return
    }
    count := 0
    for _, _card := range card_list {
        status, card_type, plate_number, err := getCardInfo(_card)
        if nil != err {
            fmt.Println(err, jsonStr, " err!!!!!!!!!! ", lineNo)
            return
        }
        if 1 != status && 4 == card_type && 0 < len(plate_number) {
            count++
        }
        if 1 < count {
            fmt.Println(err, jsonStr, " Get: ", lineNo)
            break
        }
    }
}

func getValue(mp map[string]interface{}, key string) (interface{}, error) {
    value, ok := mp[key]
    if !ok {
        if "status" == key {
            var s float64 = 0
            return s, nil
        }
        return nil, fmt.Errorf("map get key: %s fail, %+v", key, mp)
    }
    return value, nil
}

func getCardInfo(_card interface{}) (status, card_type float64, plate_number string, err error) {
    card, ok := _card.(map[string]interface{})
    if !ok {
        err = fmt.Errorf("%s", "card this data is not map")
        return
    }
    var _status interface{}
    var _card_type interface{}
    var _plate_number interface{}
    _status, err = getValue(card, "status")
    if nil != err {
        return
    }
    status = _status.(float64)
    if 1 != status {
        _card_type, err = getValue(card, "card_type")
        if nil != err {
            return
        }
        card_type = _card_type.(float64)
        if 4 == card_type {
            _plate_number, err = getValue(card, "plate_number")
            if nil != err {
                return
            }
            plate_number = _plate_number.(string)
        }
    }
    return
}
